// import { createCanvas, Image, loadImage } from 'canvas'
import fs from 'fs-extra'
import axios from 'axios'
import path from 'path'
import cy from 'crypto-js'
import { FFScene, FFText, FFVideo, FFAlbum, FFImage, FFCreator } from 'ffcreator'
import * as uuid from 'uuid'
import {createCanvas, loadImage, Image} from "canvas";
import EffectTypes = FFCreatorSpace.EffectTypes;

interface ISubLine {
  part: string
  start: number
  end: number
}

interface ITransSubLine extends ISubLine {
  english: string
}

export const transformLines = (filePath: string): ISubLine[] => {
  const jsonContent = fs.readJsonSync(filePath, 'utf-8') as ISubLine[]

  const arr: ISubLine[][] = []
  let prevContent = jsonContent[0]
  let group: ISubLine[] = []

  for (const jsonContentElement of jsonContent) {
    if (jsonContentElement.start - prevContent.end > 99) {
      arr.push(group)
      group = [jsonContentElement]
    } else {
      group.push(jsonContentElement)
    }
    prevContent = jsonContentElement
  }
  arr.push(group)

  const res = arr.map((_subArr) => {
    const len = _subArr.length
    const start = _subArr[0].start
    const end = _subArr[len - 1].end
    const sentence = _subArr.reduce((prev, next) => prev + next.part, '')
    return {
      start,
      end,
      part: sentence
    }
  })

  return res
}

type ITransResult = {
  from: 'en'
  to: 'zh'
  trans_result: { src: string; dst: string }[]
}

export const translateLines = async (sublines: ISubLine[]): Promise<ITransSubLine[]> => {
  const MD5 = cy.MD5

  const appid = ''
  const key = ''
  const salt = new Date().getTime()
  const query = sublines.map(({ part }) => part).join('\n')
  // console.log(query)
  // 多个query可以用\n连接  如 query='apple\norange\nbanana\npear'
  const from = 'zh'
  const to = 'en'
  const str1 = appid + query + salt + key
  const sign = MD5(str1)

  return axios<ITransResult>({
    method: 'post',
    headers: { 'content-type': 'application/x-www-form-urlencoded' },
    // json: true,
    data: {
      q: query,
      appid: appid,
      salt: salt,
      from: from,
      to: to,
      sign: sign
    }, // 用 qs 将js对象转换为字符串 'name=edward&age=25'
    url: 'http://api.fanyi.baidu.com/api/trans/vip/translate'
  }).then((res) => {
    const { trans_result } = res.data
    return sublines.map((item, index) => ({
      ...item,
      english: trans_result[index].dst
    }))
  })
}

const text2Image = async (prompt: string): Promise<string> => {
  try {
    const res = await axios<{images: string[]}>({
      url: 'http://127.0.0.1:7860/sdapi/v1/txt2img',
      method: 'post',
      // json: true,
      data: {
        prompt: prompt,
        steps: 20,
        pixel_perfect: true
      }
    })
    return res.data.images[0]
  } catch (e) {
    return ''
  }
}

export const text2ImageBuffer = async (prompt: string) => {
  const img = await text2Image(prompt)
  return Buffer.from(img, 'base64')
}
//
const loadImageAsync = (img: string | Buffer): Promise<Image> => {
  return new Promise((r) => {
    loadImage(img).then((m) => r(m))
  })
}

const drawText2Image = async (imgPath: string, text: string): Promise<string> => {
  const canvas = createCanvas(512, 512)
  const ctx = canvas.getContext('2d')
  const ctxImg = await loadImageAsync(imgPath)

  ctx.drawImage(ctxImg, 0, 0, 512, 512)
  ctx.font = '28px Microsoft Yahei'
  const txt = ctx.measureText(text)
  ctx.fillStyle = '#ffffff'
  ctx.fillText(text, 256 - txt.width / 2, 460)
  ctx.save()
  // ctx.restore()
  // console.log(txt.width)
  // console.log(400 - txt.width / 2)
  const targetPath = imgPath.replace('images', 'textImages')
  fs.ensureFileSync(targetPath)
  try {
    fs.writeFileSync(targetPath, canvas.toBuffer('image/png'))
  }catch (e) {
    console.log(e)
  }
  return targetPath
}

export const generateVideo = async ({
  audio,
  lines,
  cwd,
  folderName
}: {
  audio: string
  lines: ITransSubLine[]
  folderName: string
  cwd: string
}) => {
  const uidLines = lines.map((item) => ({
    ...item,
    uid: uuid.v4()
  }))

  fs.writeJsonSync(path.join(folderName, 'uidlines.json'), uidLines)
  for (const line of uidLines) {
    const image = await text2ImageBuffer(line.english)
    const saveImageFilePath = path.join(folderName, 'images', line.uid + '.png')
    fs.ensureFileSync(saveImageFilePath)
    fs.writeFileSync(saveImageFilePath, image)
  }

  const effects = [
    'fadeIn',
    'fadeOut',
    'fadeInLeft',
    'fadeInRight',
    'fadeInUp',
    'fadeInDown',
    'fadeInLeftBig',
    'fadeInRightBig',
    'fadeInUpBig',
    'fadeInDownBig',
    'fadeOutLeft',
    'fadeOutRight',
    'fadeOutUp',
    'fadeOutDown',
    'fadeOutLeftBig',
    'fadeOutRightBig',
    'fadeOutUpBig',
    'fadeOutDownBig',
    'blurIn',
    'blurOut',
    'backIn',
    'backOut',
    'backInLeft',
    'backInRight',
    'backInUp',
    'backInDown',
    'backOutLeft',
    'backOutRight',
    'backOutUp',
    'backOutDown',
    'bounceIn',
    'bounceInDown',
    'bounceInUp',
    'bounceInLeft',
    'bounceInRight',
    'bounceOut',
    'bounceOutDown',
    'bounceOutLeft',
    'bounceOutRight',
    'bounceOutUp',
    'rotateIn',
    'rotateOut',
    'rotateInDownLeft',
    'rotateInDownRight',
    'rotateInUpLeft',
    'rotateInUpRight',
    'rotateOutDownLeft',
    'rotateOutDownRight',
    'rotateOutUpLeft',
    'rotateOutUpRight',
    'rollIn',
    'rollOut',
    'zoomIn',
    'zoomInDown',
    'zoomInLeft',
    'zoomInRight',
    'zoomInUp',
    'zoomOut',
    'zoomOutDown',
    'zoomOutLeft',
    'zoomOutRight',
    'zoomOutUp',
    'slideInDown',
    'slideInLeft',
    'slideInRight',
    'slideInUp',
    'slideOutDown',
    'slideOutLeft',
    'slideOutRight',
    'slideOutUp',
    'zoomingIn',
    'zoomingOut',
    'moveingLeft',
    'moveingRight',
    'moveingUp',
    'moveingBottom',
    'fadingIn',
    'fadingOut'
  ]
  const getRandomArrItem = (arr: string | any[]): EffectTypes => {
    return arr[Math.floor(arr.length * Math.random())]
  }
  const getRandomEffect = (): EffectTypes => getRandomArrItem(effects)
  const getRandomImage = (uid: string): string => path.join(folderName, 'images', uid + '.png')

  let len = 1
  const total = uidLines.length
  const mainProcess = async () => {
    // Create FFCreator instance
    const creator = new FFCreator({
      cacheDir: path.join(cwd, '.cache'),
      outputDir: folderName,
      width: 512,
      height: 512,
      audio // background audio
    })

    await Promise.all(
      uidLines.map(async ({ english, part, start, end, uid }, index) => {
        let duration = end - start
        if(uidLines[index + 1]) {
          let gap = uidLines[index + 1].start - end
          duration += gap
        }
        const scene = new FFScene()
        scene.setBgColor('#000000')
        scene.setTransition(
          getRandomArrItem([
            'Windows4',
            'ButterflyWaveScrawler',
            'GridFlip',
            'FastSwitch',
            'Shake',
            'WaterWave',
            'InvertedPageCurl',
            'Colorful',
            'Magnifier',
            'cube',
            'hexagonalize'
          ]),
          0.5
        )
        scene.setDuration(duration / 1000 + 0.5)
        creator.addChild(scene)

        const img = getRandomImage(uid)
        const imagePath = await drawText2Image(img, part)

        // console.log(`%c img`, "color: black;background-color: pink;", img)
        const image = new FFImage({
          duration: 1,
          path: imagePath,
          resetXY: true,
          resetPos: true,
        })
        image.addEffect({
          type: 'zoomingIn',
          time: duration / 1000 * 0.7,
          delay: 0,
        });
        console.log(`-----------${len++}/${total}-----------------`)
        scene.addChild(image)
      })
    )
    creator.output(path.join(folderName, 'video.mp4'))
    creator.start() // 开始加工
    creator.closeLog() // 关闭log(包含perf)

    creator.on('start', () => {
      console.log(`FFCreator start`)
    })
    creator.on('error', (e) => {
      console.log(`FFCreator error: ${JSON.stringify(e)}`)
    })
    creator.on('progress', (e) => {
      console.log(`FFCreator progress: ${(e.percent * 100) >> 0}%`)
    })
    creator.on('complete', (e) => {
      console.log(`FFCreator completed: \n USEAGE: ${e.useage} \n PATH: ${e.output} `)
    })
  }
  mainProcess()
}
